package com.lanchetech.merchant.service.impl;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.baidu.fsg.uid.UidGenerator;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.lanchetech.bean.dto.OrderExcelDTO;
import com.lanchetech.bean.request.OrderAddressPageReq;
import com.lanchetech.bean.request.OrderCommentPageReq;
import com.lanchetech.bean.request.OrderPageReq;
import com.lanchetech.bean.response.*;
import com.lanchetech.bean.strategy.OrderMergeStrategy;
import com.lanchetech.bean.util.PageHelpUtil;
import com.lanchetech.bean.vo.OrderCommentVO;
import com.lanchetech.bean.vo.OrderDataStatisticsVO;
import com.lanchetech.bean.vo.OrderSkuVO;
import com.lanchetech.common.constants.JypConstant;
import com.lanchetech.common.enums.*;
import com.lanchetech.common.util.SensitiveInfoUtil;
import com.lanchetech.dao.*;
import com.lanchetech.entity.*;
import com.lanchetech.merchant.service.OrderService;
import com.lanchetech.service.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    OrdersMapper ordersMapper;

    @Autowired
    OrderSkuMapper orderSkuMapper;

    @Autowired
    SpuMapper spuMapper;

    @Autowired
    SkuMapper skuMapper;

    @Autowired
    OrderAddressMapper orderAddressMapper;

    @Autowired
    OrderDiscountMapper orderDiscountMapper;

    @Autowired
    AfterSaleMapper afterSaleMapper;

    @Autowired
    WxPayService wxPayService;

    @Autowired
    UserCommissionMapper userCommissionMapper;

    @Value("${domain.url}")
    private String domainUrl;

    @Resource
    UidGenerator uidGenerator;

    @Autowired
    DaoService daoService;

    @Autowired
    LogisticsService logisticsService;

    @Autowired
    CardFlowMapper cardFlowMapper;

    @Autowired
    RewardQueueMapper rewardQueueMapper;

    @Autowired
    BonusCountMapper bonusCountMapper;

    @Autowired
    UserVoucherMapper userVoucherMapper;

    @Autowired
    OrderPayMapper orderPayMapper;

    @Autowired
    ShopMapper shopMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    ConsumptionService consumptionService;

    @Autowired
    TenantFlowMapper tenantFlowMapper;

    @Autowired
    FinanceService financeService;

    @Autowired
    TenantMapper tenantMapper;

    @Autowired
    KuaidizsService kuaidizsService;

    @Autowired
    InviteFirstBuyMapper inviteFirstBuyMapper;

    @Autowired
    CommissionService commissionService;

    @Value("${wx.pay.appId}")
    private String miniAppId;

    @Value("${wx.app.appId}")
    private String appAppId;

    @Autowired
    CouponMapper couponMapper;

    @Autowired
    OrderCommentMapper orderCommentMapper;

    @Override
    public ResultData<BasePageResp<OrderResp>> getOrderPage(OrderPageReq req) {
        Page page = null;
        List<Long> orderIds = new ArrayList<>();
        List<OrderResp> orderList = new ArrayList<>();
        boolean isSkuSearch = req.getSkuId() != null || !StringUtils.isEmpty(req.getName());
        boolean isUserSearch = !StringUtils.isEmpty(req.getPhone()) || !StringUtils.isEmpty(req.getUserName());

        // 根据skuId或商品名称搜索
        if (isSkuSearch) {
            page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
            orderIds = orderSkuMapper.findAllBySkuIdAndName(req);
        }

        // 手机号或姓名搜索
        if (isUserSearch && !isSkuSearch) {
            OrderAddressPageReq orderAddressPageReq = new OrderAddressPageReq(req.getPageNo(), req.getPageSize(), req.getPhone(), req.getUserName());
            page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
            List<OrderAddress> orderAddressList = orderAddressMapper.findAllByPhoneAndName(orderAddressPageReq);
            orderIds = orderAddressList.stream().map(item -> item.getOrderId()).collect(Collectors.toList());
        }

        // 默认搜索
        if (!isUserSearch && !isSkuSearch) {
            page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
            orderList = ordersMapper.findAllBackPage(req);
            orderIds = orderList.stream().map(item -> item.getId()).collect(Collectors.toList());
        } else {
            if (!CollectionUtils.isEmpty(orderIds)) {
                req.setIds(orderIds);
                orderList = ordersMapper.findAllBackPage(req);
            }
        }

        // 如果没有数据，直接返回
        if (CollectionUtils.isEmpty(orderList)) {
            return PageHelpUtil.buildPage(orderList, page);
        }

        // 获取订单商品明细列表
        List<OrderSkuVO> orderSkuList = orderSkuMapper.findAllByOrderIds(orderIds);
        List<Long> skuIds = new ArrayList<>();
        List<Long> shopIds = new ArrayList<>();
        orderSkuList.forEach(item -> {
            if (!skuIds.contains(item.getSkuId())) {
                skuIds.add(item.getSkuId());
            }
            if (!shopIds.contains(item.getShopId())) {
                shopIds.add(item.getShopId());
            }
        });

        Map<Long, List<OrderSkuVO>> orderSkuMap = new HashMap<>();

        // 获取商品sku信息
        List<Sku> skuList = skuMapper.findAllByIds(skuIds);
        Map<Long, Sku> skuMap = new HashMap<>();
        Map<Long, User> userMap = daoService.getUserMap(orderList.stream().map(Orders::getUserId).collect(Collectors.toList()));
        Map<Long, Shop> shopMap = shopIds.isEmpty() ? new HashMap<>() : daoService.getShopMap(shopIds);
        Map<Long, Shop> tenantMap = daoService.getShopMap(orderList.stream().map(Orders::getTenantId).collect(Collectors.toList()));
        skuList.stream().forEach(item -> skuMap.put(item.getId(), item));

        // 获取收货地址
        List<OrderAddress> orderAddressList = orderAddressMapper.findAllByOrderIds(orderIds);
        Map<Long, OrderAddress> orderAddressMap = new HashMap<>();
        orderAddressList.stream().forEach(item -> orderAddressMap.put(item.getOrderId(), item));

        // 组装数据
        orderSkuList.stream().forEach((item) -> {
            if (skuMap.containsKey(item.getSkuId())) {
                item.setImage(skuMap.get(item.getSkuId()).getImage());
                item.setSpecNames(skuMap.get(item.getSkuId()).getSpecNames());
                item.setSpecValues(skuMap.get(item.getSkuId()).getSpecValues());
                item.setStockUnit(skuMap.get(item.getSkuId()).getStockUnit());
                if (orderSkuMap.containsKey(item.getOrderId())) {
                    orderSkuMap.get(item.getOrderId()).add(item);
                } else {
                    List<OrderSkuVO> list = new ArrayList<>();
                    list.add(item);
                    orderSkuMap.put(item.getOrderId(), list);
                }
            }
        });
        orderList.stream().forEach(item -> {
            item.setOrderSkuList(orderSkuMap.get(item.getId()));
            item.setOrderAddress(orderAddressMap.get(item.getId()));
            item.setUserNickname(userMap.get(item.getUserId()).getNickname());
            item.setUserAvatar(userMap.get(item.getUserId()).getAvatar());
            if (item.getShopId() != null) {
                item.setShopName(shopMap.get(item.getShopId()).getShopName());
                item.setShopAvatar(shopMap.get(item.getShopId()).getAvatar());
            }
            item.setTenantNickname(tenantMap.get(item.getTenantId()).getShopName());
            item.setTenantAvatar(tenantMap.get(item.getTenantId()).getAvatar());
        });
        return PageHelpUtil.buildPage(orderList, page);
    }

    /**
     * 商品订单列表导出数据
     * 目的：商家可以导出订单列表，发给供货商，要求供货商发货。供货商发货后，填写发货的快递公司、快递单号。商家可以上传并批量发货。
     * 需要的字段： orderId, 支付的总金额, spuId, skuId, 商品名称，购买数量，收货地址，姓名，手机号，应该
     *
     * @param req
     * @param response
     * @throws IOException
     */
    @Override
    public void exportOrderExcel(OrderPageReq req, HttpServletResponse response) throws IOException {
        ResultData<BasePageResp<OrderResp>> resp = getOrderPage(req);
        // 展开数据
        List<OrderExcelDTO> orderExcelDTOS = new ArrayList<>();
        List<Integer> orderSkuCountList = new ArrayList<>();
        boolean isEmptyIds = CollectionUtils.isEmpty(req.getCheckedIds());
        resp.getValue().getData().stream().forEach(item -> {
            // 被过滤的数量
            AtomicInteger filterCount = new AtomicInteger();
            item.getOrderSkuList().forEach(each -> {
                // 过滤未勾选的orderSku
                if (isEmptyIds || req.getCheckedIds().contains(each.getId())) {
                    orderExcelDTOS.add(OrderExcelDTO.builder()
                            .tradeNo(item.getTradeNo())
                            .spuId(each.getSpuId())
                            .skuId(each.getSkuId())
                            .totalPayAmount(item.getTotalPayAmount())
                            .productName(each.getProductName())
                            .specValues(each.getSpecValues())
                            .price(each.getPrice())
                            .count(each.getCount())
                            .stockUnit(each.getStockUnit())
                            .payTime(item.getPayTime())
                            .address(item.getOrderAddress().getMergerName() + "," + item.getOrderAddress().getAddress())
                            .name(item.getOrderAddress().getName())
                            .phone(item.getOrderAddress().getPhone())
                            .userMessage(item.getUserMessage())
                            .remark(item.getRemark())
                            .status(OrdersStatusEnum.getRemarkByStatus(item.getStatus()))
                            .logisticsStatus(LogisticsStatusEnum.getRemarkByStatus(item.getLogisticsStatus()))
                            .createdAt(item.getCreatedAt())
                            .build());
                } else {
                    filterCount.getAndIncrement();
                }
            });
            int count = item.getOrderSkuList().size() - filterCount.get();
            if (count > 0) {
                orderSkuCountList.add(count);
            }
        });

        String fileName = new String(("商品订单列表导出数据.xlsx").getBytes(), "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        OrderMergeStrategy orderMergeStrategy = new OrderMergeStrategy(orderSkuCountList);
        EasyExcel.write(response.getOutputStream(), OrderExcelDTO.class).registerWriteHandler(orderMergeStrategy).sheet("商品订单列表导出数据").doWrite(orderExcelDTOS);
    }


    @Override
    public ResultData<OrderResp> getOrderDetail(Long id) {
        Orders orders = ordersMapper.selectByPrimaryKey(id);
        OrderResp orderResp = new OrderResp();
        BeanUtils.copyProperties(orders, orderResp);

        // 获取商品信息
        List<OrderSkuVO> orderSkuList = orderSkuMapper.findAllByOrderId(orders.getId());
        List<Long> spuIds = new ArrayList<>();
        List<Long> skuIds = new ArrayList<>();
        List<Long> afterSaleIds = new ArrayList<>();
        orderSkuList.forEach(item -> {
            if (!spuIds.contains(item.getSpuId())) {
                spuIds.add(item.getSpuId());
            }
            if (!skuIds.contains(item.getSkuId())) {
                skuIds.add(item.getSkuId());
            }
            if (item.getAfterSaleId() != null) {
                afterSaleIds.add(item.getAfterSaleId());
            }
        });

        // 获取商品sku信息
        List<Sku> skuList = skuMapper.findAllByIds(skuIds);
        Map<Long, Sku> skuMap = new HashMap<>();
        skuList.stream().forEach(item -> skuMap.put(item.getId(), item));

        // 获取售后信息
        Map<Long, AfterSale> afterSaleMap = new HashMap<>();
        if (afterSaleIds.size() > 0) {
            List<AfterSale> afterSaleList = afterSaleMapper.findAllByIds(afterSaleIds);
            afterSaleList.stream().forEach(item -> afterSaleMap.put(item.getId(), item));
        }

        // 组装数据
        orderSkuList.stream().forEach((item) -> {
            item.setImage(skuMap.get(item.getSkuId()).getImage());
            item.setSpecNames(skuMap.get(item.getSkuId()).getSpecNames());
            item.setSpecValues(skuMap.get(item.getSkuId()).getSpecValues());
            item.setStockUnit(skuMap.get(item.getSkuId()).getStockUnit());
            if (item.getAfterSaleId() != null) {
                item.setAfterSaleStatus(afterSaleMap.get(item.getAfterSaleId()).getStatus());
                item.setAfterSaleCount(afterSaleMap.get(item.getAfterSaleId()).getCount());
            }
        });

        orderResp.setOrderSkuList(orderSkuList);
        orderResp.setOrderAddress(orderAddressMapper.findOneByOrderId(orders.getId()));
        orderResp.setOrderDiscountList(orderDiscountMapper.findAllByOrderId(orders.getId()));

        //获取优惠券信息
        OrderDiscount orderDiscount = orderDiscountMapper.findOneByOrderIdAndType(id, PromotionEnum.COUPON.getPromotion());
        if (orderDiscount != null) {
            orderResp.setCoupon(couponMapper.selectByPrimaryKey(orderDiscount.getRelateId()));
        }
        return new ResultData<>(orderResp);
    }

    @Override
    public BaseResp editOrderLogistics(Orders orders) {
        orders.setLogisticsStatus(LogisticsStatusEnum.DONE.getStatus());
        ordersMapper.updateOrderLogistics(orders);
        orderSkuMapper.updateLogisticsStatusByOrderId(LogisticsStatusEnum.DONE.getStatus(), orders.getId());

        //发货后订阅消息
        //发货解冻
        Orders selectOrder = ordersMapper.selectByPrimaryKey(orders.getId());
        logisticsService.unFreezeOrder(selectOrder);
        return new BaseResp();
    }

    @Override
    public BaseResp editOrderRemark(Orders orders) {
        ordersMapper.updateRemarkById(orders);

        //快递助手修改备注
        updateRemark(orders.getId());
        return new BaseResp();
    }

    private void updateRemark(Long orderId) {
        Orders orders = ordersMapper.selectByPrimaryKey(orderId);
        Shop shop = shopMapper.selectByPrimaryKey(orders.getTenantId());
        if (shop.getMallUserId() > 0) {
            KdzsPrintTradeUpdateRequest updateRequest = new KdzsPrintTradeUpdateRequest();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            updateRequest.setModified(format.format(new Date()));
            updateRequest.setTid(orders.getId().toString());
            updateRequest.setMallUserId(shop.getMallUserId());
            updateRequest.setSellerMemo(orders.getRemark());
            kuaidizsService.updateTrade(updateRequest);
        }
    }

    @Override
    public ResultData<OrderDataStatisticsVO> getOrderStatistics(OrderPageReq req) {
        return new ResultData<>(ordersMapper.getOrderDataStatistics(req));
    }

    @Override
    public ResultData<BasePageResp<OrderCommentVO>> getOrderCommentPage(OrderCommentPageReq req) {
        Merchant merchant = (Merchant) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        req.setShopId(merchant.getTenantId());
        List<OrderCommentVO> list = orderCommentMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Spu> spuMap = daoService.getSpuMap(list.stream().map(OrderCommentVO::getSpuId).collect(Collectors.toList()));
            Map<Long, Sku> skuMap = daoService.getSkuMap(list.stream().map(OrderCommentVO::getSkuId).collect(Collectors.toList()));
            Map<Long, User> userMap = daoService.getUserMap(list.stream().map(OrderCommentVO::getUserId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setUserAvatar(item.getAnonymous().equals((byte) 0) ? userMap.get(item.getUserId()).getAvatar() : JypConstant.ANONYMOUS_AVATAR);
                item.setUserNickname(item.getAnonymous().equals((byte) 0) ? userMap.get(item.getUserId()).getNickname() : SensitiveInfoUtil.chineseName(userMap.get(item.getUserId()).getNickname()));
                item.setSpecNames(skuMap.get(item.getSkuId()).getSpecNames());
                item.setSpecValues(skuMap.get(item.getSkuId()).getSpecValues());
                item.setSpuName(spuMap.get(item.getSpuId()).getName());
                item.setSpuMainImage(spuMap.get(item.getSpuId()).getMainImage());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public BaseResp auditOrderComment(Long id, Byte status) {
        Merchant merchant = (Merchant) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        OrderComment orderComment = orderCommentMapper.selectByPrimaryKey(id);
        if (orderComment.getShopId().equals(merchant.getTenantId())) {
            if (OrderCommentStatusEnum.OFFICE_CLOSE.getStatus().equals(status)) {
                if (OrderCommentStatusEnum.NORMAL.getStatus().equals(orderComment.getStatus()) || OrderCommentStatusEnum.CUSTOMER_CLOSE.getStatus().equals(orderComment.getStatus())) {
                    orderCommentMapper.updateStatusById(status, id);
                }
            }
            if (OrderCommentStatusEnum.NORMAL.getStatus().equals(status) && OrderCommentStatusEnum.OFFICE_CLOSE.getStatus().equals(orderComment.getStatus())) {
                orderCommentMapper.updateStatusById(status, id);
            }
        }
        return new BaseResp();
    }
}